Plateau
OLEM est fourni avec 2 types de plateaux : le premier est composé de carrés, le second de triangles formant des hexagones.


Pour faciliter l'utilisation de ces plateaux dans les jeux, le module board fournit les structures de données et l'API que nous utilisons pour nos propres jeux. Un éditeur de niveaux permet aussi de créer des niveaux avec une interface graphique.
Pour présenter l'API et les structures de données, nous partirons des plus petites unités pour arriver jusqu'au plateau entier.
Les plateaux et leurs composants
Éléments
Un élément représente quelque chose qui se trouve sur le plateau. Cela peut être :
- OLEM
- un objet physique (pièce de jeu), comme un mur, une figurine, des ressources
- des données liées à une position précise, invisibles pour les joueurs mais utilisables par le code du jeu. Par exemple, dans Guardian & Thieves, les positions où des trésors peuvent apparaître sont enregistrées dans le niveau, mais les trésors eux-mêmes sont générés par le code au chargement du niveau.
Structure de données
Un élément est un objet qui a :
- un type, stocké sous forme de chaîne de caractères
- des paramètres personnalisables, qui ont :
- un nom (la clé), sous forme de chaîne de caractères
- une valeur associée à ce nom, sous forme de chaîne de caractères (comme une table de hachage ou un objet JSON)
API
"""
Constructeur de la classe
:param type_string: type, chaîne de caractères
"""
Element(type_string)
"""
Renvoie le paramètre type de l'élément. Donne le même résultat que get_param("type").
"""
get_type()
"""
Renvoie la valeur du paramètre donné
:param param_name: nom du paramètre à lire
Renvoie la valeur associée, sous forme de chaîne de caractères
"""
get_param(param_name)
"""
Modifie la valeur d'un paramètre. Si un paramètre du même nom existe
déjà, sa valeur est remplacée, sinon il est créé.
:param param_name: nom du paramètre
:param value: valeur associée au nom, sous forme de chaîne de caractères
"""
set_param(param_name, value)
Conteneurs
Pour placer des éléments sur le plateau, on les stocke dans des conteneurs. Il existe 3 types de conteneurs :
- le nœud (Node)
- la case (Cell)
- la bordure (Border)
Ces types sont expliqués plus en détail dans la section Tuiles ci-dessous.
Structure de données
Un conteneur est une liste d'éléments.
API
"""
Vérifie si le conteneur contient au moins un élément d'un
type donné
:param type: type à vérifier
Renvoie un booléen
"""
has_element_type(type)
"""
Ajoute un élément au conteneur.
:param element: objet Element à stocker dans le conteneur
"""
add_element(element)
"""
Retire un élément du conteneur. L'élément n'est PAS détruit.
:param element: objet Element à retirer du conteneur
"""
remove_element(element)
"""
Retire tous les éléments du conteneur.
"""
clear_elements()
"""
Renvoie la liste des éléments du conteneur.
"""
get_elements()
"""
Renvoie le premier élément du type donné.
:param string_type: type à chercher
Renvoie un objet Element
"""
get_element_by_type(string_type)
"""
Renvoie tous les éléments du type donné.
:param string_type: type à chercher
Renvoie une liste d'objets Element
"""
get_elements_by_type(string_type)
"""
Vérifie si le conteneur contient des éléments.
Renvoie un booléen
"""
is_empty()
Tuiles
Les tuiles sont les unités de base que l'on répète pour créer un plateau. Leur forme dépend du type de plateau, mais elles suivent toutes une structure commune, construite avec les conteneurs présentés ci-dessus :
- les nœuds sont des positions entre les cases du plateau, où OLEM peut se trouver (d'autres éléments peuvent aussi y être placés). Il y a un seul nœud par tuile
- les cases sont, eh bien, les cases classiques d'un jeu de plateau
- les bordures sont les zones entre les cases, où l'on peut par exemple placer des murs
Structure de données
Une tuile contient :
- ses coordonnées (x, y) sur le plateau
- un nœud
- un tableau de cases
- un tableau de bordures
Tuile carrée

Pour le plateau composé de carrés, une tuile est définie ainsi :
avec :
- 1, le nœud
- 2, la case (ici, il n'y en a qu'une)
- 3, la bordure du haut
- 4, la bordure de gauche
Tuiles triangulaires


avec :
- 1 le nœud
- 2 les cases
- 3 les bordures
API
"""
Renvoie une bordure de la tuile
:param id: sur un plateau carré, 0 est la bordure horizontale du haut, 1 la bordure verticale de gauche
Renvoie un conteneur
"""
get_border(id)
"""
Renvoie la case de la tuile
Renvoie un conteneur
"""
get_cell()
"""
Renvoie le nœud de la tuile
Renvoie un conteneur
"""
get_node()
"""
Renvoie la coordonnée x de la tuile
"""
get_x()
"""
Renvoie la coordonnée y de la tuile
"""
get_y()
"""
Vérifie si les cases, le nœud et les bordures sont tous vides
Renvoie un booléen
"""
is_empty()
Plateau
Un plateau est un objet qui a :
- un nombre de colonnes
- un nombre de lignes
- des tuiles d'une dimension donnée (largeur et hauteur, en mm)
- un nom
- un tableau de paramètres personnalisables
- un tableau de tuiles
En plaçant plusieurs tuiles côte à côte, on obtient cette structure (capture de l'éditeur de niveaux) :
REMARQUE : avec cette structure, certains conteneurs sont en fait en dehors du plateau, car certains nœuds sont sur le bord du plateau
"""
Crée un plateau carré vide
NB : voir genericboard.load_board() pour charger un plateau créé avec l'éditeur de niveaux
:param rows: nombre de lignes
:param columns: nombre de colonnes
:param tile_width: largeur d'une tuile en mm
:param tile_height: hauteur d'une tuile en mm
Renvoie un objet squareboard
"""
squareboard(rows, columns, tile_width, tile_height)
"""
Affiche toutes les tuiles du plateau, avec un chiffre par tuile.
0 indique une tuile vide, 1 une tuile non vide
"""
print()
"""
Détruit l'objet plateau
NB : pour l'instant, il faut l'appeler manuellement pour éviter une fuite
mémoire. Nous cherchons un moyen de le détruire automatiquement, car
c'est un problème quand le script plante.
"""
__del__()
"""
Renvoie le nombre de lignes du plateau
Renvoie un entier
"""
get_row_count()
"""
Renvoie le nombre de colonnes du plateau
Renvoie un entier
"""
get_column_count()
"""
Vérifie si une position est valide sur le plateau
:param x: coordonnée x sur le plateau
:param y: coordonnée y sur le plateau
Renvoie un booléen
"""
is_position_within_board(x, y)
"""
Renvoie la tuile à une position donnée
:param x: coordonnée x sur le plateau
:param y: coordonnée y sur le plateau
Renvoie un objet tile, ou None si la tuile n'existe pas
"""
get_tile(x, y)
"""
Renvoie le nom du niveau
Renvoie une chaîne de caractères
"""
get_name()
"""
Renvoie la valeur du paramètre donné
:param param_name: nom du paramètre à lire
Renvoie la valeur associée, sous forme de chaîne de caractères
"""
get_param(param_name)
"""
Modifie la valeur d'un paramètre. Si un paramètre du même nom existe
déjà, sa valeur est remplacée, sinon il est créé.
:param param_name: nom du paramètre
:param value: valeur associée au nom, sous forme de chaîne de caractères
"""
set_param(param_name, value)
########################################
# Non implémenté ou non testé
get_tile_dimension
get_tiles
get_neighbor_tiles
get_border_from_tile(tile, direction)
get_border_from_position(x, y, direction)
Fonctions statiques
Ces fonctions ne s'appellent pas sur les objets
"""
Crée un plateau à partir d'un fichier json généré par l'éditeur de niveaux
:param path_to_file: chemin du plateau dans le système de fichiers
Renvoie un objet squareboard
"""
genericboard.load_board(path_to_file)
Exemple
Exemple simple
import genericboard
import olem
TYPE_START = "start"
TYPE_WALL = "wall"
TYPE_END = "end"
def find_starting_pos(b):
for y in range(b.get_row_count()):
for x in range(b.get_column_count()):
tile = b.get_tile(x, y)
node = tile.get_node()
if (node.has_element_type(TYPE_START)):
print("found start at " + str(x) + " " + str(y))
return (x, y)
def is_node_walkable(board, x, y):
board_edge = False
if not board.is_position_within_board(x, y):
board_edge = True
if not board.is_position_within_board(x - 1, y):
board_edge = True
if not board.is_position_within_board(x, y - 1):
board_edge = True
if board_edge:
print("board edge is not walkable")
return False
has_wall = False
tile = board.get_tile(x, y)
if tile.get_node().has_element_type(TYPE_WALL):
has_wall = True
if tile.get_border(0).has_element_type(TYPE_WALL):
has_wall = True
if tile.get_border(1).has_element_type(TYPE_WALL):
has_wall = True
if(has_wall):
print("target tile has walls")
return False
print("looking left")
tile = board.get_tile(x - 1, y)
if tile.get_border(0).has_element_type(TYPE_WALL):
return False
print("looking up")
tile = board.get_tile(x, y - 1)
if tile.get_border(1).has_element_type(TYPE_WALL):
return False
return True
def get_command():
msg = olem.gmsg_wait_for_message()
if msg == "up":
return (0, -1)
if msg == "down":
return (0, 1)
if msg == "left":
return (-1, 0)
if msg == "right":
return (1, 0)
return (0, 0)
def end_reached(board, current_position):
tile = board.get_tile(current_position[0], current_position[1])
return tile.get_node().has_element_type(TYPE_END)
print("Board tester")
b = genericboard.load_board("/tmp/board_tester")
b.print()
starting_position = find_starting_pos(b)
current_position = starting_position
while not end_reached(b, current_position):
command = get_command()
if is_node_walkable(b, current_position[0] + command[0], current_position[1] + command[1]):
current_position = (current_position[0] + command[0], current_position[1] + command[1])
print("Moved to " + str(current_position[0]) + " " + str(current_position[1]))
else:
print("Node " + str(current_position[0] + command[0]) + " " + str(current_position[1] + command[1]) + " is not walkable")
print("End reached")
b.__del__()